package com.hd.manager.webSocket;

//import com.Service.OpenRecordService;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hd.appcommon.entity.Door;
import com.hd.appcommon.entity.OpenRecord;
import com.hd.appcommon.entity.Room;
import com.hd.appcommon.entity.User;
import com.hd.appcommon.service.DoorService;
import com.hd.appcommon.service.OpenRecordService;
import com.hd.appcommon.service.RoomService;
import com.hd.appcommon.service.UserService;
import com.hd.appcommon.service.impl.OpenRecordServiceImpl;
import com.hd.appcommon.utils.DateFormatUtil;
import com.hd.appcommon.utils.TimeStampUtil;
import com.hd.manager.config.WebSocketConfigurator;
import com.hd.manager.util.ImageUtil;
import com.hd.manager.util.JieShiActivateRequestCallBackUtil;
import com.hd.manager.util.JieShiActivateRequestUtil;
import com.hd.manager.util.ZhengYuanUtil;
import com.itextpdf.text.pdf.codec.TIFFConstants;
import com.taobao.api.internal.toplink.channel.websocket.WebSocketServerChannel;
import lombok.extern.slf4j.Slf4j;
import okhttp3.WebSocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.awt.*;
import java.io.IOException;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;

import static com.hd.manager.util.RequestIdUtil.getRequestId;
import static com.hd.manager.webSocket.EndpointManager.ipExist;

@Service
@ServerEndpoint(value="/devices/{deviceId}", configurator = WebSocketConfigurator.class)
@Component
@Slf4j
public class DeviceEndpoint {
    private static OpenRecordService openRecordService;
    private static RoomService roomService;
    private static DoorService doorService;
    private static UserService userService;
    private static ZhengYuanUtil zhengYuanUtil;
//    private static JieShiActivateRequestUtil jieShiActivateRequestUtil;
    private static JieShiActivateRequestCallBackUtil jieShiActivateRequestCallBackUtil;
    private static ImageUtil imageUtil;
    // 线程安全的HashMap long型 的pkgId  String型的message
//    private static final ConcurrentHashMap<Long,String> productMap = new ConcurrentHashMap<>();

    @Autowired
    public void DeviceEndpoint(OpenRecordService openRecordService, RoomService roomService,
                               DoorService doorService, UserService userService,
                               ZhengYuanUtil zhengYuanUtil,
                               JieShiActivateRequestUtil jieShiActivateRequestUtil,
                               JieShiActivateRequestCallBackUtil jieShiActivateRequestCallBackUtil,
                               ImageUtil imageUtil) {
        DeviceEndpoint.openRecordService = openRecordService;
        DeviceEndpoint.roomService = roomService;
        DeviceEndpoint.doorService = doorService;
        DeviceEndpoint.userService = userService;
        DeviceEndpoint.zhengYuanUtil = zhengYuanUtil;
//        DeviceEndpoint.jieShiActivateRequestUtil = jieShiActivateRequestUtil;
        DeviceEndpoint.jieShiActivateRequestCallBackUtil = jieShiActivateRequestCallBackUtil;
        DeviceEndpoint.imageUtil = imageUtil;
    }

    // Session
    private Session session;
    private String deviceId;
    private String ipAddr;

    public String getIpAddr() {
        return ipAddr;
    }

    public void setIpAddr(String ipAddr) {
        this.ipAddr = ipAddr;
    }

    public Session getSession() {
        return session;
    }

    public String getDeviceId() {
        return deviceId;
    }

    /**
     * 建立连接方法
     *
     * @param session 连接信息
     */
    @OnOpen
    public void onOpen(@PathParam("deviceId") String deviceId, Session session) {
        session.setMaxTextMessageBufferSize(1024*1024);
        session.setMaxBinaryMessageBufferSize(1024*1024);
        if (!checkDeviceId(deviceId)) {
            try {
                session.close();
            }
            catch (IOException e) {

            }
            return;
        }

        this.session = session;
        this.deviceId = deviceId;
        Map<String, Object> userProperties = session.getUserProperties();
        this.ipAddr = (String) userProperties.get(WebSocketConfigurator.IP_ADDR);
        log.info("捕获IP: "+ipAddr);
        EndpointManager.addEnpoint(this);
    }


    /**
     * 连接关闭
     */
    @OnClose
    public void onClose() {
        EndpointManager.removeEndpoint(this);
    }


    /**
     * 收到客户端消息后调用方法
     *
     * @param message
     * @param session
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        // 解析json字符串，根据相应的协议格式处理自己的业务逻辑，同时按照协议进行响应回写
        System.out.println("收到客户端消息："+message);
        JSONObject jsonObject = JSON.parseObject(message);
        String responseJson = processMessage(message);
        if (responseJson != null && !responseJson.isEmpty()){
            sendMessage(responseJson);
        }

    }

//    public String getMessage(Long requestId){
//        if(!productMap.isEmpty()&&productMap.containsKey(requestId)&&!productMap.get(requestId).equals("")){
//            String message = productMap.get(requestId);
//            productMap.remove(requestId);
//            return message;
//        }
//        else
//            return "";
//    }

//    /**
//     * 将消费需求挂上map
//     * @param requestId
//     */
//    public void setVoidKey(Long requestId){
//        productMap.put(requestId,"");
//    }

    // 解析json字符串，根据相应的协议格式处理自己的业务逻辑，同时根据协议生成响应json
    public String processMessage(String message) {
        JSONObject jsonObject = JSON.parseObject(message);

        String resp_type = jsonObject.getString("resp_type");
        if(!StringUtils.isEmpty(resp_type)){
            return responseProcess(jsonObject);
        }
        String request_type = jsonObject.getString("request_type");
        String responseJson = "";
        switch (request_type) {
            case "deviceOnline":
                System.out.println("进入deviceOnline");
                responseJson = "{ \"resp_type\":\"deviceOnline\", \"device_id\":\""+deviceId+"\", \"code\":0, \"log\":\"'deviceOnline' success\", \"hb_interval\": 40 }";
                break;
            case "heartbeat":
                System.out.println("进入heartbeat");
                responseJson = "{ \"resp_type\":\"heartbeat\", \"code\":0, \"log\":\"'heartbeat'success\" }";
                break;
            case "faceRecognition":
                String ip = jsonObject.getString("IP");
                log.info("信息携带的ip"+ip);
                if(!ipExist(ip)){
                    log.info("非法ip! "+ip);
                    return null;
                }
                log.info("面部识别");
                log.info(message);
                System.out.println("进入faceRecognition");
                String jobNumber = jsonObject.getString("user_id");
                String base64 = jsonObject.getString("image");
                Boolean access = false;
//                判断抓拍到的用户是否登记了信息
                Door door = doorService.getOne(new QueryWrapper<Door>().eq("device_id",deviceId));
                if(!door.getIp().equals(ip)){
                    log.info("ip鉴权失败！");
                    return null;
                }
                Integer roomId = door.getRoomId();
                Room room = roomService.getById(roomId);
                String userIdList = room.getUserIdList();
                String[] userIdsList = userIdList.split(",");
                for (String s:
                     userIdsList) {
                    if(s.equals(jobNumber)){
                        access = true;
                    }
                }
                // 有进入权限的做开门和记录开门数据的处理
                if(access){
                    Date date = new Date();
                    String now = TimeStampUtil.TimeStampToString(date.getTime());
                    String facePicture = imageUtil.savePicture(now.substring(0,10)+getRequestId()+jobNumber,base64);
                    String deviceId = jsonObject.getString("device_id");
                    String timestamp = jsonObject.getString("timestamp");
                    OpenRecord openRecord = new OpenRecord();
                    openRecord.setFacePicturePath(facePicture);
                    String openTime = DateFormatUtil.timeStamp2Date(timestamp);
                    openRecord.setUserId(jobNumber);
                    openRecord.setDeviceId(deviceId);
                    Date openDate = TimeStampUtil.StringToDate(openTime);
                    openRecord.setOpenTime(openDate);
                    // 获取门设备一方面是为了获取门设备信息，另一方面是为发出远程开门指令
                    String doorLockCode = door.getDoorLockCode();

                    openRecord.setDoorName(door.getDoorName());
                    openRecord.setDoorId(door.getDoorId());

                    openRecord.setRoomId(room.getId());
                    openRecord.setRoomName(room.getRoomName());

                    openRecord.setBuildingName(room.getBuildingName());
                    User user = userService.getOne(new QueryWrapper<User>().eq("job_number",jobNumber).last("LIMIT 1"));
                    if(user!=null){
                        openRecord.setUserName(user.getName());
                        Integer operatorType;
                        if(user.getType().equals("1")){
                            //学生
                            operatorType = 0;
                        }else {
                            operatorType = 1;
                        }

                        Boolean success = zhengYuanUtil.RemoteOpen(doorLockCode,operatorType,jobNumber);
                        // 开门
                        openRecord.setSuccess(success);
                    }else {
                        openRecord.setSuccess(false);
                    }

                    openRecordService.save(openRecord);
                    responseJson = "{ \"code\":0, \"resp_type\":\"faceRecognition\", \"frpic_name\":\""+jsonObject.getString("frpic_name")+"\", \"log\":\"'faceRecognition'success\" }";
                }
                // 没有权限的不管了
                break;
            default:
        }
        return responseJson;
    }

    private String responseProcess(JSONObject jsonObject) {
        String respType = jsonObject.getString("resp_type");
        log.info("开始接受返回数据流程");
        /* 生产者： 提供主动发起请求接口的返回数据*/
        if(!StringUtils.isEmpty(respType)){
            Long requestId = Long.valueOf(jsonObject.getString("request_id"));
//            if(requestId!=null&&productMap.containsKey(requestId)){
//                log.info("消息map插入信息");
//                productMap.put(requestId,jsonObject.toString());
//            }
            jieShiActivateRequestCallBackUtil.setMessage(requestId,jsonObject);
        }
        return null;
    }

    /**
     * 服务器主动推送数据
     *
     * @param message
     * @throws IOException
     */
    public void sendMessage(String message) {
        if(session==null){
            log.error("杰视会话未连接");
            return;
        }
        if (session.isOpen())
            session.getAsyncRemote().sendText(message);
    }

    /**
     * 发生异常时
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }


    // 检查deviceId是否可以接入
    private boolean checkDeviceId(String deviceId) {
        return true;
    }

}
